package ru.mirent.json;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import ru.mirent.json.entity.SerializeRawJson;

import java.util.function.Function;

public class ObjectToJson implements Function<Object, String> {
    private JsonMapper jsonMapper;

    public ObjectToJson() {
        // Переопределение принтера для вывода элементов массивов каждого с новой строки
        DefaultPrettyPrinter defaultPrettyPrinter = new DefaultPrettyPrinter();
        defaultPrettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE);

        jsonMapper = JsonMapper.builder()
                // Настройка маппера
                .disable(MapperFeature.USE_ANNOTATIONS)
                .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
                // Настройка сериализатора
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
                // Указание поведения для разных полей при сериализации объекта
                .visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
                .visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.ANY)
                .visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
                .visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE)
                // Добавление модуля сериализации значений
                .addModule(new SimpleModule().addSerializer(String.class, new SerializeRawJson()))
                // Переобпередение принтера по умолчанию
                .defaultPrettyPrinter(defaultPrettyPrinter)
                .build();
    }

    @Override
    public String  apply(Object object) {
        if (object == null) {
            return null;
        }

        try {
            return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            return null;
        }
    }
}
